#ifndef _TASK_PACKAGE__HPP_
#define _TASK_PACKAGE__HPP_
/**
 * @file TaskPakage.hpp
 * @author HuLiang (2472708282@qq.com)
 * @brief 约定csn中传输任务数据包的格式
 * @version 0.1
 * @date 2023-01-13
 *
 * @copyright Copyright (c) 2023
 *
 */
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>

namespace csn {

#define EXT_MSG_LEN 256

#pragma pack(1)
typedef struct {
  uint32_t id;                        // task id
  uint64_t ts_ms;                     // timestamp in milliseconds
  uint32_t psize;                     // size of payload
  uint8_t ext_msg[EXT_MSG_LEN] = {0}; // extra message
} pkgHeader;
#pragma pack()

class TaskPackage {
public:
  TaskPackage(pkgHeader header) : header_(header) {
    payload_ = new uint8_t[header.psize];
  }
  TaskPackage(std::string s)
  : header_(pkgHeader{0, 0, static_cast<uint32_t>(s.length())}) {
    payload_ = new uint8_t[s.length() + 1];
    payload_[s.length()] = 0;
    memcpy(payload_, s.c_str(), s.length());
  }
  TaskPackage(pkgHeader header, char *buf) : header_(header) {
    payload_ = new uint8_t[header.psize];
    memcpy(payload_, buf, header.psize);
  }
  TaskPackage(uint32_t id, uint64_t ts_ms, std::vector<uint8_t> &buff)
      : header_(pkgHeader{id, ts_ms, static_cast<uint32_t>(buff.size())}) {
    payload_ = new uint8_t[buff.size()];
    memcpy(payload_, buff.data(), buff.size());
  }
  ~TaskPackage() {
    if (payload_) {
#ifdef DEBUG_INFO
      std::stringstream ss;
      ss << "release pkg @" << std::hex << (void *)payload_ << std::endl;
      std::cout << ss.str();
#endif
      delete[] payload_;
    }
  }
  void show_content() {
    char *buf = nullptr;
    try {
      buf = new char[header_.psize + 1];
      buf[header_.psize] = '\0';
      memcpy(buf, payload_, header_.psize);
      std::cout << buf << std::endl;
      delete[] buf;
      buf = nullptr;
    } catch (const std::exception &e) {
      std::cerr << e.what() << '\n';
      if (buf)
        delete[] buf;
    }
  }
  uint8_t *getPayload() const { return payload_; }
  uint32_t getPayloadSize() const { return header_.psize; }
  pkgHeader getPackageHeader() const { return header_; }
  uint8_t *getExtMsg() { return header_.ext_msg; }

private:
  uint8_t *payload_ = NULL; // payload_
  pkgHeader header_;        // Header
};

typedef std::shared_ptr<TaskPackage> TaskPackage_ptr;

class FileTaskPackage : public TaskPackage {
public:
  FileTaskPackage(uint32_t id, uint64_t pts, std::string file_name)
      : TaskPackage(pkgHeader{id, pts, file_size(file_name)}) {
    std::ifstream file(file_name, std::ios::binary);
    file.read((char *)getPayload(), size_);
    memcpy(getExtMsg(), file_name.c_str(), file_name.length());
  }

private:
  uint32_t file_size(std::string file_name) {
    std::ifstream file(file_name, std::ios::binary);
    file.seekg(std::ios::beg, std::ios::end);
    size_ = static_cast<uint32_t>(file.tellg());
    file.seekg(std::ios::beg, std::ios::beg);
    file.close();
    return size_;
  }

private:
  uint32_t size_;
};

} // namespace csn

#endif //_TASK_PACKAGE__HPP_
